home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Advanced I⁄O v2.3 / Advanced i⁄o / endian_io.h < prev    next >
Text File  |  1996-02-02  |  7KB  |  228 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               Class Endian_IO
  6.  *    to read integers of various sizes taking the byte order
  7.  *                into account
  8.  *              and bit-stream IO
  9.  *
  10.  *   Two different byte orders are supported
  11.  *    bigendian    - most significant byte first
  12.  *    littleendian    - most significant byte last
  13.  *
  14.  * $Id: endian_io.h,v 2.1 1995/03/02 18:06:20 oleg Exp oleg $
  15.  *
  16.  ************************************************************************
  17.  */
  18.  
  19. #ifndef __GNUC__
  20. #pragma once
  21. #endif
  22. #ifndef endian_io_h
  23. #define endian_io_h
  24.  
  25. #ifdef __GNUC__
  26. #pragma interface
  27. #endif
  28.  
  29. #include <fstream.h>
  30. #include "myenv.h"
  31.  
  32. #ifdef __GNUC__
  33. #define _IOS_Bin_               ios::bin
  34. #else
  35. #define _IOS_Bin_               ios::binary
  36. #endif
  37.  
  38.                 // Extension to 'ios' to keep byte order
  39.                 // and stream sharing info
  40. class EndianIOData : virtual public ios
  41. {
  42.   enum { MSBfirst, LSBfirst } byte_order;
  43.   bool shared;            // Was this stream shared with some other
  44.                 // stream?
  45.  
  46. public:
  47.                 // Means having this stream reference the same
  48.                 // disk structure *and* the memory buffer
  49.                 // as a_file
  50.   void share_with(EndianIOData& a_file);
  51.   void unshare(void);        // Check for sharing and break it
  52.   EndianIOData(void) : byte_order(LSBfirst), shared(false)  {}
  53.   ~EndianIOData(void)        { unshare(); }
  54.  
  55.   void set_bigendian(void)          // Most significant byte first
  56.                   { byte_order = MSBfirst; }
  57.   void set_littlendian(void)        // Least significant byte first
  58.                 { byte_order = LSBfirst; }
  59.   bool q_MSBfirst(void) const    { return byte_order == MSBfirst; }
  60.   bool was_shared(void) const    { return shared; }
  61.                 // Returns TRUE if something goes wrong
  62.                 // with the I/O
  63.   bool operator ! ()    { return !good(); }
  64.   void error(const char *descr);
  65.                 // Make sure the stream was opened successfully
  66.   void assert_open(const char * file_name);
  67. };
  68.  
  69.             // Class to read (binary) data from the input stream
  70.             // keeping in mind the byte order
  71. class EndianIn : public EndianIOData, public ifstream
  72. {
  73. public:
  74.   EndianIn(void) {}
  75.   EndianIn(const char * file_name) : ifstream(file_name,ios::in|_IOS_Bin_)
  76.                 { assert_open(file_name); }
  77.   ~EndianIn(void)         { unshare(); }
  78.  
  79.                     // Open by example. File handle of
  80.                     // 'file' is dup-ed, so closing the
  81.                     // present file would not close 'file'
  82.   EndianIn(EndianIn& file)        { share_with(file); }
  83.  
  84.   void open(const char *name, int mode=ios::in|_IOS_Bin_)
  85.         { ifstream::open(name,mode); assert_open(name); }
  86.  
  87.   void close(void);        // Close the stream breaking sharing if any
  88.  
  89.                 // The following I/O functions take
  90.                 // the char string op_description
  91.                 // that tells what this operation is for
  92.                 // On error, this string is printed along
  93.                 // with the error description
  94.   unsigned char  read_byte(const char * op_description);
  95.   unsigned short read_short(const char * op_description);
  96.   unsigned long  read_long(const char * op_description);
  97. };
  98.  
  99. inline unsigned char EndianIn::read_byte(const char * op_description) 
  100. {
  101.   unsigned char c;
  102.   if( !get(c) )
  103.     error(op_description);
  104.   return c;
  105. }
  106.  
  107.             // Class to write (binary) data from the input stream
  108.             // keeping in mind the byte order
  109. class EndianOut : public EndianIOData, public ofstream
  110. {
  111. public:
  112.   EndianOut(void) {}
  113.   EndianOut(const char * file_name)
  114.     : ofstream(file_name,ios::out|ios::trunc|_IOS_Bin_)
  115.                 { assert_open(file_name); }
  116.   ~EndianOut(void)         { unshare(); }
  117.  
  118.                     // Open by example. File handle of
  119.                     // 'file' is dup-ed, so closing the
  120.                     // present file would not close 'file'
  121.   EndianOut(EndianOut& file)        { share_with(file); }
  122.  
  123.   void open(const char *name, int mode=ios::out|ios::trunc|_IOS_Bin_, int prot=0644)
  124.         { ofstream::open(name,mode); assert_open(name); }
  125.  
  126.   void close(void);        // Close the stream
  127.  
  128.                 // The following I/O functions take
  129.                 // the char string op_description
  130.                 // that tells what this operation is for
  131.                 // On error, this string is printed along
  132.                 // with the error description
  133.  
  134.                 // Note, the first operand of write_byte
  135.                 // has to be specified as 'int' rather
  136.                 // than 'unsigned char', as bizarre as
  137.                 // it may seem. Otherwise, write_byte(0xff)
  138.                 // results in the i/o error
  139.                 // 'Inappropriate IOCTL for device'
  140.                 // after some 2000-4000 writings such a byte.
  141.   void write_byte(const int item, const char * op_description = "");
  142.   void write_short(const unsigned short item, const char* op_description = "");
  143.   void write_long(const unsigned long item, const char * op_description = "");
  144. };
  145.  
  146. /*
  147.  *------------------------------------------------------------------------
  148.  *            Bit-stream Input-Output
  149.  * Note, bits are written in first-in first-out mode
  150.  */
  151.  
  152. class BitIOBuffer
  153. {
  154. protected:
  155.   unsigned char buffer;
  156.   enum { largest_bit_in_buffer = (1<<7) };
  157.   unsigned char curr_bit_pos;
  158. public:
  159.   BitIOBuffer(void) : buffer(0), curr_bit_pos(largest_bit_in_buffer) {}
  160. };
  161.  
  162. class BitIn : BitIOBuffer, public EndianIn
  163. {
  164. public:
  165.             // This is a dummy constructor. Use open() function
  166.             // of EndianIO class to perform the actual opening
  167.   BitIn(void) {}
  168.  
  169.   int  get_bit(void);            // Get a bit from the input stream
  170.   short get_short(void);        // Get a short integer that was written
  171.                       // using a variable size code
  172. };
  173.  
  174. class BitOut : BitIOBuffer, public EndianOut
  175. {
  176. public:
  177.             // This is a dummy constructor. Use open() function
  178.             // of EndianIO class to perform the actual opening
  179.   BitOut(void) {}
  180.   ~BitOut(void);
  181.  
  182.   void put_bit(const char bit);        // Write a bit into the output stream
  183.   void put_short(const short item);    // Write a signed short integer 
  184.                       // using a variable size code
  185.   void close(void);            // Close the stream
  186. };
  187.  
  188.             // Put a bit (0/1) into the bit stream
  189. inline void BitOut::put_bit(const char bit)
  190. {
  191.   if( bit )
  192.     buffer |= curr_bit_pos;
  193.   if( (curr_bit_pos>>=1) == 0 )
  194.     write_byte(buffer), curr_bit_pos = largest_bit_in_buffer, buffer = 0;
  195. }
  196.  
  197.             // Flush the bit buffer on closing the stream      
  198. inline void BitOut::close(void)
  199. {
  200.                     // If the buffer contains something
  201.   if( curr_bit_pos != largest_bit_in_buffer )
  202.   {
  203.     write_byte(buffer);            // Flush the buffer
  204.     curr_bit_pos = largest_bit_in_buffer, buffer = 0;
  205.   }
  206.   EndianOut::close();
  207. }
  208.  
  209. inline BitOut::~BitOut(void)                { close(); }
  210.  
  211.  
  212.             // Read a bit from the bit stream
  213. inline int BitIn::get_bit(void)
  214. {
  215.   if( curr_bit_pos & largest_bit_in_buffer )
  216.   {
  217.     if( eof() ) 
  218.       error("Reading an 8-bit chunk");
  219.     get(buffer);
  220.   }
  221.   unsigned char bit_pos = curr_bit_pos;
  222.   if( (curr_bit_pos >>=1) == 0 )
  223.     curr_bit_pos = largest_bit_in_buffer;
  224.   return buffer & bit_pos ? 1 : 0;
  225. }
  226.  
  227. #endif
  228.